package com.mspbots.cw.amqp.receivers;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.cw.amqp.BaseReceiver;
import com.mspbots.cw.amqp.model.ExceptionLog;
import com.mspbots.cw.amqp.model.TimeEntry;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * com.mspbots.core.connectwise.listeners.TimeEntriesListener
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/7/29
 */
@Log4j2
@Component
@RequiredArgsConstructor
public class TimeEntriesReceiver extends BaseReceiver {

    private final RabbitMessagingTemplate messagingTemplate;

    @RabbitListener(queues = "core.entries")
    public void processMessage(TimeEntry content) {
        try{
            log.debug("core.entries {} is time entry cw id: {}", content.getTenantId(), content.getCwTid());

            if (content.getEndDate() != null && content.getEndDate()
                    .isBefore(LocalDateTime.of(2000, 1, 1, 0, 0))) {
                content.setEndDate(null);
            }
            content.setUpdatedBy(content.getExtend().get("_info").get("updatedBy").asText());
            content.setChargeToId(ObjectUtils.isEmpty(content.getExtend().get("chargeToId")) ? null :
                    content.getExtend().get("chargeToId").asLong());
            content.setResolutionFlag(content.getExtend().get("addToResolutionFlag").asBoolean());
            content.setSyncTime(LocalDateTime.now());

            JsonNode workTypeNode = content.getExtend().get("workType");
            content.setWorkTypeName(ObjectUtils.isEmpty(workTypeNode) ? null : workTypeNode.get("name").asText());
            content.setWorkTypeId(ObjectUtils.isEmpty(workTypeNode) ? null : workTypeNode.get("id").asInt());

            Optional<Long> id = this.databaseClient.execute("SELECT id FROM tenant_time_entry " +
                    "WHERE tenant_id =:tenantId AND cw_tid =:cwId")
                    .as(Long.class)
                    .bind("tenantId", content.getTenantId())
                    .bind("cwId", content.getCwTid())
                    .fetch().one().blockOptional(Duration.ofSeconds(10));

            // fixed:  [22021] invalid byte sequence for encoding "UTF8": 0x00
            if (!ObjectUtils.isEmpty(content.getDescription())){
                content.setDescription(content.getDescription().replaceAll("\0", ""));
                // fixed: [22P05] unsupported Unicode escape sequence
                ((ObjectNode)content.getExtend()).put("notes",content.getDescription());
            }


            if (id.isPresent() && id.get() > 0) {
                content.setAction("update");
                content.setId(id.get());
                content.setSyncTime(LocalDateTime.now());
                this.databaseClient.update().table(TimeEntry.class).using(content).fetch().rowsUpdated().block(Duration.ofSeconds(10));
                log.debug("Time entry,update,id:{}:::{}", id.get(), this.objectMapper.convertValue(content, JsonNode.class));
            } else {
                content.setAction("new");
                this.databaseClient.insert().into(TimeEntry.class).using(content).fetch().rowsUpdated().block(Duration.ofSeconds(10));
                log.debug("Time entry,new,id:{}", this.objectMapper.convertValue(content, JsonNode.class));
            }

            this.messagingTemplate.convertAndSend("msp.trigger.timeentry", "", content);

        }catch (Exception e){
            this.databaseClient.insert().into(ExceptionLog.class).using(
                    ExceptionLog.builder()
                            .tenantId(content.getTenantId().intValue())
                            .name("core.entries")
                            .status(500)
                            .type("core.entries")
                            .msg(e.getMessage()+","+objectMapper.convertValue(content,JsonNode.class).toString() )
                            .build()
            ).fetch().rowsUpdated().block(Duration.ofSeconds(10));
        }
    }
}
